package hos.map.geometry;

import java.util.Map;
import java.util.Set;

import hos.map.coordinate.CoordinateType;
import hos.map.coordinate.LatLng;
import hos.map.distance.DistanceCalculator;
import hos.map.tool.CalculatorUtils;

/**
 * <p>Title: Circle </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2023-12-08 18:11
 */
public class Circle extends Geometry  {

    private final LatLng center;
    private int radius;

    private DistanceCalculator mDistanceCalculator;

    public static Circle fromMap(Map<String, Double> dataMap, int radius, CoordinateType type) {
        if (dataMap == null) {
            return null;
        }
        return new Circle(LatLng.fromMap(dataMap, type), radius, type);
    }

    public static Circle fromMapLatLng(Map<String, Object> dataMap, CoordinateType type) {
        if (dataMap == null) {
            return null;
        }
        int radius = (int) dataMap.get("radius");

        if (type == null) {
            String typeName = (String) dataMap.get("type");
            type = CoordinateType.form(typeName);
        }
        @SuppressWarnings("unchecked")
        Map<String, Object> center = (Map<String, Object>) dataMap.get("center");
        Circle circle = new Circle(LatLng.fromMapLatLng(center), radius, type);
        if (dataMap.containsKey("json")) {
            circle.setJson((String) dataMap.get("json"));
        }
        if (dataMap.containsKey("id")) {
            circle.id = (String) dataMap.get("id");
        }
        return circle;
    }

    public Circle(LatLng center, int radius, CoordinateType type) {
        super(type);
        this.center = center;
        this.radius = radius;
    }

    public Circle(LatLng center, int radius) {
        super(center.getType());
        this.center = center;
        this.radius = radius;
    }

    /**
     * 获取中心点位
     */
    public LatLng getCenter() {
        return center;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public Circle toBaiDu() {
        LatLng point = center.toBaiDu();
        return new Circle(point, radius, CoordinateType.bd09mc);
    }

    @Override
    public Circle toAMap() {
        LatLng point = center.toBaiDu();
        return new Circle(point, radius, CoordinateType.gcj02);
    }

    @Override
    public Circle toWgs() {
        LatLng point = center.toBaiDu();
        return new Circle(point, radius, CoordinateType.wgs84);
    }

    @Override
    public Map<String, Object> toMap() {
        Map<String, Object> data = super.toMap();
        data.put("radius", radius);
        data.put("center", center.toMap());
        return data;
    }

    @Override
    public String toJson() {
        Map<String, Object> data = toMap();
        Set<String> keySet = data.keySet();
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        for (String key : keySet) {
            if (builder.length() > 1) {
                builder.append(",");
            }
            builder.append("\"").append(key)
                    .append("\"").append(":");
            if (key.equals("center")) {
                String jsonData = center.toJson();
                builder.append(jsonData);
            } else {
                Object value = data.get(key);
                if (value instanceof String) {
                    builder.append("\"")
                            .append(value)
                            .append("\"");
                } else {
                    builder.append(value);
                }
            }
        }
        builder.append("}");
        return builder.toString();
    }

    public void setDistanceCalculator(DistanceCalculator mDistanceCalculator) {
        this.mDistanceCalculator = mDistanceCalculator;
    }

    /**
     * 判断点位是否在圆内
     *
     * @param point 目标点位
     */
    public boolean isInside(final LatLng point) {
        if (mDistanceCalculator != null) {
            return mDistanceCalculator.isPointInside(center, radius, point);
        }
        return CalculatorUtils.isPointInsideVincenty(center, radius, point);
    }
}
